package top.yueyazhui.module.rest_template.util;

import cn.hutool.core.util.ObjectUtil;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @description
 * @author yueyazhui
 * @website yueyazhui.top
 * @email yueyazhui@sina.com
 * @date 2023-11-12 17:44
 */
@Component
public class RestTemplateUtil {
 
    private static RestTemplate restTemplate;
 
    @Resource
    private RestTemplate processedRestTemplate;
 
    @PostConstruct
    public void init() {
        restTemplate = processedRestTemplate;
    }

    public static String buildUrl(String hostAddress, String uri) {
        return hostAddress + uri;
    }
 
    public static String buildUrl(String scheme, String host, int port, String uri) {
        return scheme + "://" + host + ":" + port + uri;
    }

    public static <T> ResponseEntity<T> get(String uri, Map<String, String> headers, Map<String, Object> uriVariables, Map<String, Object> queryVariables, Class<T> clazz) {
        return execute(uri, HttpMethod.GET, headers, uriVariables, queryVariables, null, clazz);
    }
 
    public static <T> ResponseEntity<T> get(String uri, Map<String, Object> uriVariables, Map<String, Object> queryVariables, Class<T> clazz) {
        return execute(uri, HttpMethod.GET, null, uriVariables, queryVariables, null, clazz);
    }
 
    public static <T> ResponseEntity<T> get(String uri, String token, Map<String, Object> queryVariables, Class<T> clazz) {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Auth-Token", token);
        return execute(uri, HttpMethod.GET, headers, null, queryVariables, null, clazz);
    }
 
    public static <T> ResponseEntity<T> get(String uri, Map<String, Object> queryVariables, Class<T> clazz) {
        return execute(uri, HttpMethod.GET, null, null, queryVariables, null, clazz);
    }
 
    public static <T> ResponseEntity<T> get(String uri, String token, Class<T> clazz) {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Auth-Token", token);
        return execute(uri, HttpMethod.GET, headers, null, null, null, clazz);
    }
 
    public static <T> ResponseEntity<T> get(String uri, Class<T> clazz) {
        return execute(uri, HttpMethod.GET, null, null, null, null, clazz);
    }
 
    public static <T> ResponseEntity<T> post(String uri, Map<String, String> headers, Map<String, Object> uriVariables, Map<String, Object> queryVariables, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.POST, headers, uriVariables, queryVariables, body, clazz);
    }
 
    public static <T> ResponseEntity<T> post(String uri, Map<String, Object> uriVariables, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.POST, null, uriVariables, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> post(String uri, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.POST, null, null, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> post(String uri, String token, Map<String, Object> uriVariables, Object body, Class<T> clazz) {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Auth-Token", token);
        return execute(uri, HttpMethod.POST, headers, uriVariables, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> post(String uri, String token, Object body, Class<T> clazz) {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Auth-Token", token);
        return execute(uri, HttpMethod.POST, headers, null, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> put(String uri, Map<String, String> headers, Map<String, Object> uriVariables, Map<String, Object> queryVariables, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.PUT, headers, uriVariables, queryVariables, body, clazz);
    }
 
    public static <T> ResponseEntity<T> put(String uri, Map<String, Object> uriVariables, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.PUT, null, uriVariables, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> put(String uri, String token, Map<String, Object> uriVariables, Object body, Class<T> clazz) {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Auth-Token", token);
        return execute(uri, HttpMethod.PUT, headers, uriVariables, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> put(String uri, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.PUT, null, null, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> put(String uri, String token, Object body, Class<T> clazz) {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Auth-Token", token);
        return execute(uri, HttpMethod.PUT, headers, null, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> patch(String uri, Map<String, String> headers, Map<String, Object> uriVariables, Map<String, Object> queryVariables, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.PATCH, headers, uriVariables, queryVariables, body, clazz);
    }
 
    public static <T> ResponseEntity<T> patch(String uri, Map<String, Object> uriVariables, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.PATCH, null, uriVariables, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> patch(String uri, String token, Map<String, Object> uriVariables, Object body, Class<T> clazz) {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Auth-Token", token);
        return execute(uri, HttpMethod.PATCH, headers, uriVariables, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> patch(String uri, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.PATCH, null, null, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> patch(String uri, String token, Object body, Class<T> clazz) {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("X-Auth-Token", token);
        return execute(uri, HttpMethod.PATCH, headers, null, null, body, clazz);
    }
 
    public static <T> ResponseEntity<T> delete(String uri, Map<String, String> headers, Map<String, Object> uriVariables, Map<String, Object> queryVariables, Class<T> clazz) {
        return execute(uri, HttpMethod.DELETE, headers, uriVariables, queryVariables, null, clazz);
    }
 
    public static <T> ResponseEntity<T> delete(String uri, Map<String, Object> uriVariables, Class<T> clazz) {
        return execute(uri, HttpMethod.DELETE, null, uriVariables, null, null, clazz);
    }
 
    public static <T> ResponseEntity<T> delete(String uri, Map<String, Object> uriVariables, Object body, Class<T> clazz) {
        return execute(uri, HttpMethod.DELETE, null, uriVariables, null, body, clazz);
    }
 
    /**
     * HTTP/HTTPS请求
     *
     * @param uri           请求地址
     * @param httpMethod    请求方法
     * @param headers       请求头
     * @param uriVariables  路径参数
     * @param queryVariables 查询参数
     * @param body          请求体
     * @param clazz         返回值类型
     * @return ResponseEntity<T>
     */
    private static <T> ResponseEntity<T> execute(String uri, HttpMethod httpMethod, Map<String, String> headers, Map<String, Object> uriVariables, Map<String, Object> queryVariables, Object body, Class<T> clazz) {
        HttpEntity<?> httpEntity = new HttpEntity<>(body, buildHeader(headers));
        return restTemplate.exchange(buildUri(uri, uriVariables, queryVariables), httpMethod, httpEntity, clazz);
    }
 
    /**
     * 组装请求头
     *
     * @param headers 传入的请求头
     * @return HttpHeaders
     */
    private static HttpHeaders buildHeader(Map<String, String> headers) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Content-Type", "application/json;charset=UTF-8");
        httpHeaders.add("Accept-Charset", "UTF-8");
        httpHeaders.add("Accept", "application/json;charset=UTF-8");
        // 拼接传入的请求头
        if (ObjectUtil.isNotEmpty(headers)) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                httpHeaders.set(entry.getKey(), entry.getValue());
            }
        }
        return httpHeaders;
    }
 
    /**
     * 组装查询参数
     *
     * @param uri 请求地址
     * @param uriVariables 路径参数
     * @param queryVariables 查询参数
     * @return URI
     */
    private static URI buildUri(String uri, Map<String, Object> uriVariables, Map<String, Object> queryVariables) {
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(uri);
        if (Objects.nonNull(uriVariables)) {
            uriComponentsBuilder.uriVariables(uriVariables);
        }
        if (ObjectUtil.isNotEmpty(queryVariables)) {
            for (Map.Entry<String, Object> entry : queryVariables.entrySet()) {
                uriComponentsBuilder.queryParam(entry.getKey(), entry.getValue());
            }
        }
        return uriComponentsBuilder.build().encode().toUri();
    }
}